using System.Net;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Services.Initial.PublicProject.PublicClass.ExtensionException;
using Services.Identity.Domain;
using Services.Identity.Domain.Entities;
using Services.Identity.Domain.ValueObject;

namespace Services.Identity.Infrastructure;
public class IdentityRepository : IIdentityRepository
{
    private readonly RoleManager<Role> roleManager;
    private readonly MyIdentityUserManager userManager;
    private readonly MyIdentityDbContext myIdentityDbContext;
    public IdentityRepository(RoleManager<Role> roleManager, MyIdentityUserManager userManager, MyIdentityDbContext myIdentityDbContext)
    {
        this.roleManager = roleManager;
        this.userManager = userManager;
        this.myIdentityDbContext = myIdentityDbContext;
    }
    /// <summary>
    /// 添加errorMessage
    /// </summary>
    /// <param name="msg"></param>
    /// <returns></returns>
    private static IdentityResult ErrorResult(string msg)
    {
        IdentityError idError = new IdentityError { Description = msg };
        return IdentityResult.Failed(idError);
    }
    public async Task<IdentityResult> AddRoleAsync(string roleName)
    {
        if (!await this.roleManager.RoleExistsAsync(roleName))
        {
            var role = Role.Create(roleName);
            var result = await this.roleManager.CreateAsync(role);
            if (result.Succeeded)
            {
                return result;
            }
            else
            {
                return ErrorResult("出现错误，未清楚");
            }
        }
        return ErrorResult($"{roleName}已存在,请核对后重新输入");
    }

    public async Task<bool> AddRolePermissionsAsync(Role role, List<PermissionNameAndRouter> permissionNameAndRouters)
    {
        foreach (var item in permissionNameAndRouters)
        {
            role.UserPermissions.Add(UserPermission.Create(item.PermissionName, item.RouterName));
        }
        return await this.myIdentityDbContext.SaveChangesAsync() > 0;
    }

    public async Task<IdentityResult> AddUserAsync(string userName, string userPhone, string password)
    {
        var user = User.Create(userName, userPhone);
        var userNames = this.userManager.Users.IgnoreQueryFilters().Where(x => x.UserName == userName).ToList();
        if (userNames.Count > 0)
        {
            throw new ExceptionWithStatus(HttpStatusCode.BadRequest, "用户名已存在");
        }
        var userPhones = this.userManager.Users.IgnoreQueryFilters().Where(x => x.PhoneNumber == userPhone).ToList();
        if (userPhones.Count > 0)
        {
            throw new ExceptionWithStatus(HttpStatusCode.BadRequest, "手机号已存在");
        }
        return await this.userManager.CreateAsync(user, password);
    }

    public async Task<IdentityResult> AddUserToRoleAsync(string userName, string roleName)
    {
        var user = await this.userManager.FindByNameAsync(userName) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, $"未找到该{userName}对应的user");
        var role = await this.roleManager.FindByNameAsync(roleName) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, $"未找到该{roleName}对应的role");
        await this.userManager.AddToRoleAsync(user!, role!.Name!);
        return IdentityResult.Success;
    }

    public async Task<(IdentityResult result, User user)> CheckUserNameAndPasswordAsync(string userName, string password)
    {
        var user = await this.userManager.FindByNameAsync(userName) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, $"未找到该{userName}对应的user");
        if (await this.userManager.IsLockedOutAsync(user))
        {
            throw new ExceptionWithStatus(HttpStatusCode.Locked, $"{userName}已被锁定，请耐心等待可用时间，距离可用时间还有{user.LockoutEnd}");
        }
        var result = await this.userManager.CheckPasswordAsync(user, password);
        if (!result)
        {
            throw new ExceptionWithStatus(HttpStatusCode.Unauthorized, $"{userName}所对应的密码错误");
        }
        else
        {
            return (IdentityResult.Success, user);
        }
    }

    public async Task<(IdentityResult result, User user)> CheckUserPhoneAndPasswordAsync(string userPhone, string password)
    {
        var user = await this.userManager.Users.FirstOrDefaultAsync(x => x.PhoneNumber == userPhone) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, "未找到该userPhone对应的user");
        if (await this.userManager.IsLockedOutAsync(user))
        {
            throw new ExceptionWithStatus(HttpStatusCode.Locked, $"{userPhone}已被锁定，请耐心等待可用时间，距离可用时间还有{user.LockoutEnd}");
        }
        var result = await this.userManager.CheckPasswordAsync(user, password);
        if (!result)
        {
            throw new ExceptionWithStatus(HttpStatusCode.Unauthorized, $"{userPhone}所对应的密码错误");
        }
        else
        {
            return (IdentityResult.Success, user);
        }
    }

    public async Task<IdentityResult> DeleteRoleAsync(string roleName)
    {
        var role = await this.roleManager.FindByNameAsync(roleName) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, $"未找到该{roleName}对应的role");
        return await this.roleManager.DeleteAsync(role!);
    }

    public async Task<bool> DeleteRolePermissionsAsync(Role role, string[] permissions)
    {
        foreach (var item in permissions)
        {
            var permission = role.UserPermissions.Find(x => x.PermissionNameAndRouter.PermissionName == item || x.PermissionNameAndRouter.RouterName==item) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, $"未找到该{item}对应的permission");
            this.myIdentityDbContext.Permissions.Remove(permission);
            role.UserPermissions.Remove(permission);
        }
        return await this.myIdentityDbContext.SaveChangesAsync() > 0;
    }

    public async Task<IdentityResult> DeleteUserAsync(string userName)
    {
        var user = await this.userManager.Users.FirstOrDefaultAsync(x => x.UserName == userName) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, $"未找到该{userName}对应的user");
        var userLoginStore = this.userManager.UserLoginStore;
        var noneCT = default(CancellationToken);
        //一定要删除aspnetuserlogins表中的数据，否则再次用这个外部登录登录的话
        //就会报错：The instance of entity type 'IdentityUserLogin<Guid>' cannot be tracked because another instance with the same key value for {'LoginProvider', 'ProviderKey'} is already being tracked.
        //而且要先删除aspnetuserlogins数据，再软删除User
        var logins = await userLoginStore.GetLoginsAsync(user, noneCT);
        foreach (var login in logins)
        {
            await userLoginStore.RemoveLoginAsync(user, login.LoginProvider, login.ProviderKey, noneCT);
        }
        user.SoftDelete();
        return await this.userManager.UpdateAsync(user);
    }

    public async Task<string[]> GetAllRoleNamesAsync()
    {
        var roles = await this.roleManager.Roles.ToArrayAsync();
        if (roles.Length == 0)
        {
            throw new ExceptionWithStatus(HttpStatusCode.NotFound, "未找到任何角色信息");
        }
        return roles.Select(r => r.Name).ToArray()!;
    }

    public async Task<Role> GetRoleAsync(string roleName)
    {
        //var role = (await this.roleManager.FindByNameAsync(roleName)) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, "未找到角色信息");
        var role = await this.myIdentityDbContext.Roles.Include(x => x.UserPermissions).FirstOrDefaultAsync(r => r.Name == roleName) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, "未找到角色信息");
        return role!;
    }

    public Task<List<PermissionNameAndRouter>> GetRolePermissionsAsync(Role role)
    {
        var list = new List<PermissionNameAndRouter>();
        foreach (var item in role.UserPermissions)
        {
            list.Add(item.PermissionNameAndRouter);
        }
        return Task.FromResult(list);
    }

    public async Task<string[]> GetRolesByUserAsync(User user)
    {
        var roles = await this.userManager.GetRolesAsync(user);
        return roles.ToArray()!;
    }

    public async Task<User> GetUserInformationByIdAsync(string id)
    {
        return await this.userManager.FindByIdAsync(id) ?? throw new ExceptionWithStatus(HttpStatusCode.NotFound, "未找到用户信息");
    }

    public async Task<List<User>> GetUserInformationByNamesync(string name)
    {
        return await Task.FromResult(this.myIdentityDbContext.Users.Where(x => x.UserName!.Contains(name)).ToList());
    }
}